package cn.xeblog.plugin.tools.read.api;

import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.xeblog.plugin.tools.read.entity.Chapter;
import cn.xeblog.plugin.tools.read.entity.LegadoBook;
import cn.xeblog.plugin.tools.read.error.LegadoApiException;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * Legado接口
 *
 * @author LYF
 * @date 2022-07-14
 */
public class LegadoApi {

    /**
     * 端口
     */
    private static final int PORT = 1122;
    /**
     * 服务地址
     */
    private final String server;
    /**
     * http客户端
     */
    private final HttpClient client;

    /**
     * 构造
     *
     * @param host 主机ip
     */
    public LegadoApi(String host) {
        // 服务地址
        this.server = StrUtil.format("http://{}:{}", host, PORT);
        // http客户端
        this.client = HttpClient.newBuilder().connectTimeout(Duration.ofMillis(5000)).build();
    }

    /**
     * 测试连接
     *
     * @return true, 成功, 否则, false
     */
    public boolean testConnect() {
        HttpRequest request = HttpRequest.newBuilder(URI.create(server)).build();
        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            return response.statusCode() == 200;
        } catch (Exception ignored) {
        }
        return false;
    }

    /**
     * 获取书架
     *
     * @return 书架列表
     * @throws LegadoApiException
     */
    public List<LegadoBook> getBookshelf() throws LegadoApiException {
        String url = UrlBuilder.of(this.server).addPath("getBookshelf").build();
        String errorMsg = "[Legado]书架获取失败";
        JSONObject result = get(url, errorMsg);
        return handleArray(result, LegadoBook.class, errorMsg);
    }

    /**
     * 获取章节信息
     *
     * @param bookUrl 书籍地址
     * @return 章节列表
     * @throws LegadoApiException 获取失败，抛出
     */
    public List<Chapter> getChapterList(String bookUrl) throws LegadoApiException {
        // 请求接口
        String url = UrlBuilder.of(this.server).addPath("getChapterList").addQuery("url", bookUrl).build();
        String errorMsg = "[Legado]章节列表获取失败";
        JSONObject result = get(url, errorMsg);

        // 处理结果
        return handleArray(result, Chapter.class, errorMsg);
    }

    /**
     * 获取章节内容
     *
     * @param bookUrl 书籍访问地址
     * @param index   章节下标
     * @return 章节内容
     */
    public String getBookContent(String bookUrl, int index) {
        String url = UrlBuilder.of(this.server).addPath("getBookContent").addQuery("url", bookUrl).addQuery("index", index).build();
        String errorMsg = "书籍内容获取失败";
        try {
            JSONObject result = get(url, errorMsg);
            if (result != null && StrUtil.isNotBlank(result.getStr("errorMsg"))) {
                return result.getStr("errorMsg");
            }
            return handleStr(result, errorMsg);
        } catch (LegadoApiException e) {
            return errorMsg;
        }
    }

    /**
     * 保存书籍信息
     *
     * @param bookInfo 书籍信息
     */
    public void saveBookProgress(LegadoBook bookInfo) {
        String url = UrlBuilder.of(this.server).addPath("saveBookProgress").build();
        post(url, bookInfo);
    }

    /**
     * 发送get请求
     *
     * @param url      访问地址
     * @param errorMsg 错误信息
     * @return 获取的请求结果json
     * @throws LegadoApiException Legado接口异常
     */
    private JSONObject get(String url, String errorMsg) throws LegadoApiException {
        HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build();
        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() == 200) {
                return JSONUtil.parseObj(response.body());
            }
        } catch (Exception e) {
            LegadoApiException.throwException(errorMsg);
        }
        return null;
    }

    /**
     * 发送post请求
     *
     * @param url  访问地址
     * @param body 参数body（json）
     */
    private void post(String url, Object body) {
        HttpRequest request = HttpRequest.newBuilder(URI.create(url)).POST(HttpRequest.BodyPublishers.ofString(JSONUtil.toJsonStr(body))).header("Content-Type", "application/json").build();
        try {
            client.send(request, HttpResponse.BodyHandlers.ofString());
        } catch (Exception ignored) {
        }
    }

    /**
     * 处理数组
     *
     * @param result      结果json
     * @param elementType 元素类型（如Chapter.class、LegadoBook.class）
     * @param errorMsg    错误的消息
     * @param <T>         指定的类型
     * @return 元素类型的列表
     * @throws LegadoApiException 请求失败，抛出
     */
    private <T> List<T> handleArray(JSONObject result, Class<T> elementType, String errorMsg) throws LegadoApiException {
        // 请求成功
        if (result != null && result.getBool("isSuccess")) {
            // 将json转成指定的实例
            JSONArray data = result.getJSONArray("data");
            return JSONUtil.toList(data, elementType);
        }
        LegadoApiException.throwException(errorMsg);
        return new ArrayList<>();
    }

    /**
     * 处理字符串
     *
     * @param result   结果json
     * @param errorMsg 错误信息
     * @return 处理好的字符串
     * @throws LegadoApiException Legado接口异常
     */
    private String handleStr(JSONObject result, String errorMsg) throws LegadoApiException {
        // 请求成功，返回请求结果数据
        if (result != null && result.getBool("isSuccess")) {
            return result.getStr("data", "");
        }
        LegadoApiException.throwException(errorMsg);
        return "";
    }
}
